package com.bytedance.common.plugin.framework.so;

import android.annotation.SuppressLint;
import android.util.Log;

import com.bytedance.common.plugin.framework.compat.SupportedArchitectures;
import com.bytedance.common.plugin.framework.util.PluginUtil;
import com.bytedance.common.utility.Logger;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

public class PluginLibExtractor {
    private static String TAG = PluginLibExtractor.class.getSimpleName();
    private static Set<String> sSupportedAbis;

    static {
        Set<String> supportedAbis = SupportedArchitectures.supportedAbis();
        if (Logger.debug()) {
            Logger.d("PluginLibExtractor", supportedAbis.toString());
        }

        if (supportedAbis.size() > 0) {
            sSupportedAbis = supportedAbis;
        } else {
            sSupportedAbis = new LinkedHashSet();
            sSupportedAbis.add("armeabi");
        }
    }

    public PluginLibExtractor() {

    }

    public static void reloadLibs(File apkFile, File outputLibDir) {
        try {
            outputLibDir.mkdir();
            if (!outputLibDir.isDirectory()) {
                throw new IOException("Failed to create lib directory " + outputLibDir.getPath());
            }

            File[] soFiles = outputLibDir.listFiles(new FileFilter() {
                @Override
                public final boolean accept(File pathname) {
                    return pathname.getName().endsWith(".so");
                }
            });
            if (soFiles == null) {
                Log.w(TAG, "Failed to list plugin lib dir content (" + outputLibDir.getPath() + ").");
            } else {
                int length = soFiles.length;
                for (int i = 0; i < length; ++i) {
                    File soFile = soFiles[i];
                    Log.i(TAG, "Trying to delete old file " + soFile.getPath() + " of size " + soFile.length());
                    if (!soFile.delete()) {
                        Log.w(TAG, "Failed to delete old file " + soFile.getPath());
                    } else {
                        Log.i(TAG, "Deleted old file " + soFile.getPath());
                    }
                }
            }

            if (extractLibs(new ZipFile(apkFile), outputLibDir)) {
                Log.i(TAG, "The plugin is contains .so files.");
            } else {
                Log.i(TAG, "The plugin isn\'t contain any .so files.");
            }
        } catch (Exception e) {
            Logger.e(TAG, e.getMessage());
        }
    }

    @SuppressLint(value = {"DefaultLocale"})
    private static boolean extractLibs(ZipFile apkFile, File outputLibDir) throws IOException {
        HashMap<String, LinkedList<ZipEntry>> map = new HashMap();
        Enumeration<? extends ZipEntry> enumeration = apkFile.entries();
        while (enumeration.hasMoreElements()) {
            ZipEntry zipEntry = enumeration.nextElement();
            String name = zipEntry.getName();
            if (name.startsWith("/")) {
                name = name.substring(1);
            }

            if (!name.startsWith("lib/")) {
                continue;
            }

            if (zipEntry.isDirectory()) {
                continue;
            }

            int index = name.indexOf(47, 4);
            String arch = index > 0 ? name.substring(4, index).toLowerCase() : "armeabi";
            LinkedList<ZipEntry> list = map.get(arch);
            if (list == null) {
                list = new LinkedList();
                map.put(arch, list);
            }
            list.add(zipEntry);
        }
        Iterator<String> iterator = sSupportedAbis.iterator();
        LinkedList<ZipEntry> supportedArchZipEntryList;
        do {
            if (iterator.hasNext()) {
                String abi = iterator.next();
                if (abi == null) {
                    continue;
                }
                if (!map.containsKey(abi)) {
                    continue;
                }
                supportedArchZipEntryList = map.get(abi);
                break;
            } else {
                supportedArchZipEntryList = null;
                break;
            }
        } while (true);

        if (Logger.debug()) {
            Logger.d(TAG, "get arch = " + supportedArchZipEntryList + " lib so");
        }

        supportedArchZipEntryList = supportedArchZipEntryList == null ? map.get("armeabi") : supportedArchZipEntryList;
        if (supportedArchZipEntryList != null) {
            if (!outputLibDir.exists()) {
                outputLibDir.mkdirs();
            }
            Iterator<ZipEntry> it = ((List) supportedArchZipEntryList).iterator();
            while (it.hasNext()) {
                ZipEntry zipEntry = it.next();
                String name = zipEntry.getName();
                PluginUtil.writeToFile(apkFile.getInputStream(zipEntry), new File(outputLibDir, name.substring(name.lastIndexOf(47) + 1)));
            }
            return true;
        }
        return false;
    }
}

